<template>
    <!-- contaner -->
    <div class="scrollbar-container" ref="scrollbarSpanRef" @mouseenter="moveEnterScrollBar" :style="{width:scrollWidth,height:scrollHeight}"
    @mouseleave="mouseLeaveScrollBar" @mouseup="mouseUpSlider" @mousemove="mouseMoveSlider($event)">
        <!--  fixed span -->
        <div class="scroll-fixed-span" ref="scrollFixedSpanRef" :style="scrollFixedSpanStyle" @scroll="scrollWheel">
            <!-- content span -->
            <div class="content-span" ref="contentSpanRef" :style="contentSpanStyle">
                <slot></slot>
            </div>
        </div>
        <!-- scrollY -->
        <transition name="vertical-slider">
            <div class="scrollbar-bar-span vertical-bar-span" v-if="moveEnterShowY" :style="{width : setSliderWidth + 'px'}">
                <div class="scrollbar-bar-slider slider-y" ref="sliderVerticalRef" :style="verticalSliderStyle" @mousedown="mouseDownSliderY($event)">
                </div>
            </div>
        </transition>
        <!-- scrollX -->
        <transition name="horizontal-slider">
            <div class="scrollbar-bar-span horizontal-bar-span" v-if="moveEnterShowX" :style="{height : setSliderHeight + 'px'}">
                <div class="fixed-slider fixed-slider-left" :style="{width:fixedSliderWidth + 'px'}"></div>
                <div class="scrollbar-bar-slider slider-x" ref="sliderHorizontalRef" :style="horizontalSliderStyle" @mousedown="mouseDownSliderX($event)">
                </div>
                <div class="fixed-slider fixed-slider-right" :style="{width:fixedSliderWidth + 'px'}"></div>
            </div>
        </transition>
    </div>
</template>

<script>
    export default {
        name: "scroller-bar",
        props: {
            isShowHorizontal : {
                type: Boolean,
                default: false // x
            },
            isShowVertical : {
                type: Boolean,
                default: false //y
            },
            sliderColor: {
                type: String,
                default: '#8c939d'
            },
            activeSliderColor : {
                type: String,
                default: '#6b7380'
            },

            //container width,height
            width: {
                type: String,
                default: '100%'
            },
            height: {
                type: String,
                default: '100%'
            },
            sliderWidth: {
                type: Number,
                default: 9
            },
            sliderHeight: {
                type: Number,
                default: 9
            },
        },
        data : function(){
            return {
                setShowHorizontal: this.isShowHorizontal,
                setShowVertical: this.isShowVertical,

                moveEnterShowY: false,
                moveEnterShowX: false,

                setSliderColor: this.sliderColor,
                setActiveSliderColor: this.activeSliderColor,

                scrollLeftWidth: 25,
                scrollBottomHeight: 25,

                scrollFixedSpanStyle: {
                    width: '100%',
                    height: '100%'
                },

                contentSpanStyle: {
                    minWidth: '100%',
                    height: 'auto',
                    borderBottom: '0px',
                    borderLeft: '0px',
                    display: 'inline-block'
                },
                scrollWidth: this.width,
                scrollHeight: this.height,

                //y
                verticalSliderStyle: {
                    marginTop: '0px',
                    height: '0px',
                    backgroundColor: '',
                    display: 'block'
                },
                canMoveSliderY: false,
                sliderY: {
                    downY: 0,
                },
                setSliderWidth: this.sliderWidth,

                //x
                horizontalSliderStyle: {
                    marginLeft: '0px',
                    weight: '0px',
                    backgroundColor: '',
                    display: 'block'
                },
                canMoveSliderX: false,
                sliderX: {
                    downX: 0,
                },
                setSliderHeight: this.sliderHeight,

                sliderSite: {
                    x: 0,
                    y: 0
                },
                observers: [],
                fixedSliderWidth : 0
            }
        },
        methods: {
            scrollWheel: function(event){
                if(this.setShowVertical){
                    setVerticalSliderStyle(this);
                }
                if(this.setShowHorizontal){
                    setHorizontalSliderStyle(this);
                }

                //save slider site
                const scrollFixedSpanTarget =  this.$refs['scrollFixedSpanRef'];
                if(scrollFixedSpanTarget != null){
                    this.sliderSite.x = scrollFixedSpanTarget.scrollLeft;
                    this.sliderSite.y = scrollFixedSpanTarget.scrollTop;
                }
            },
            moveEnterScrollBar: function(){
                if(this.setShowVertical){
                    this.moveEnterShowY = true;
                }
                if(this.setShowHorizontal){
                    this.moveEnterShowX = true;
                }
            },
            mouseLeaveScrollBar: function(){
                resetSlider(this);
            },
            mouseDownSliderY: function(event){
                if(this.setShowVertical){
                    this.verticalSliderStyle.backgroundColor = this.setActiveSliderColor;
                    this.canMoveSliderY = true;
                    this.sliderY.downY = event.screenY;
                }
            },
            mouseDownSliderX: function(event){
                if(this.setShowHorizontal){
                    this.horizontalSliderStyle.backgroundColor = this.setActiveSliderColor;
                    this.canMoveSliderX = true;
                    this.sliderX.downX = event.screenX;
                }
            },
            mouseUpSlider: function(){
                if(this.setShowVertical){
                    this.verticalSliderStyle.backgroundColor = this.setSliderColor;
                }
                if(this.setShowHorizontal){
                    this.horizontalSliderStyle.backgroundColor = this.setSliderColor;
                }
                this.canMoveSliderY = false;
                this.canMoveSliderX = false;
            },
            mouseMoveSlider: function(event){
                if(this.canMoveSliderY && this.moveEnterShowY){
                    const curY = event.screenY;
                    const preY = this.sliderY.downY;
                    const moveY = curY - preY;

                    const sliderYHeight = this.$refs['sliderVerticalRef'].offsetHeight;
                    const scrollbarHeight = this.$refs['scrollbarSpanRef'].offsetHeight;
                    const sliderCanMove = scrollbarHeight - sliderYHeight;
                    const contentSpanHeight = this.$refs['contentSpanRef'].offsetHeight;
                    const scrollCanMoveY = contentSpanHeight - scrollbarHeight;
                    const scrollY = moveY / sliderCanMove * scrollCanMoveY;

                    this.sliderY.downY =  this.sliderY.downY + moveY;
                    const sliderScrollTop = this.$refs['scrollFixedSpanRef'].scrollTop;

                    this.sliderSite.y = sliderScrollTop + scrollY;
                    this.$refs['scrollFixedSpanRef'].scrollTo(this.sliderSite.x,this.sliderSite.y);
                }
                if(this.canMoveSliderX && this.moveEnterShowX){
                    const curX = event.screenX;
                    const preX = this.sliderX.downX;
                    const moveX = curX - preX;

                    const sliderXWidth = this.$refs['sliderHorizontalRef'].offsetWidth;
                    const scrollbarWidth = this.$refs['scrollbarSpanRef'].offsetWidth;
                    const sliderCanMove = scrollbarWidth - sliderXWidth;
                    const contentSpanWidth = this.$refs['contentSpanRef'].offsetWidth;
                    const scrollCanMoveX = contentSpanWidth - scrollbarWidth;
                    const scrollX = moveX / sliderCanMove * scrollCanMoveX;

                    this.sliderX.downX =  this.sliderX.downX + moveX;
                    const sliderScrollLeft = this.$refs['scrollFixedSpanRef'].scrollLeft;

                    this.sliderSite.x = sliderScrollLeft + scrollX;
                    this.$refs['scrollFixedSpanRef'].scrollTo(this.sliderSite.x,this.sliderSite.y);
                }
            }
        },
        mounted: function(){
            let setScrollWidth = '100%';
            let setScrollOverflowX = 'scroll';
            let setScrollHeight = '100%';
            let setScrollOverflowY = 'scroll';
            if(this.setShowVertical){
                // set sliderY
                setScrollWidth = 'calc(100% + ' + this.scrollLeftWidth + 'px)';
                this.contentSpanStyle.borderRight = this.scrollLeftWidth + 'px';
            }else{
                setScrollWidth = '100%';
                setScrollOverflowY = 'hidden';
                this.contentSpanStyle.borderRight = '0px';
            }
            if(this.setShowHorizontal){
                //set sliderX
                setScrollHeight = 'calc(100% + '+ this.scrollBottomHeight + 'px)';
                this.contentSpanStyle.borderBottom = this.scrollBottomHeight + 'px';
            }else{
                setScrollHeight = '100%';
                setScrollOverflowX = 'hidden';
                this.contentSpanStyle.borderBottom = '0px';
            }
            this.scrollFixedSpanStyle = {
                width : setScrollWidth,
                overflowX : setScrollOverflowX,
                height : setScrollHeight,
                overflowY : setScrollOverflowY
            };

            //sliderY style
            this.verticalSliderStyle.backgroundColor = this.setSliderColor;

            //sliderX style
            this.horizontalSliderStyle.backgroundColor = this.setSliderColor;

            //set listening
            listenContentElement(this);
        },
        destroyed: function(){
           //销毁
           //取消监听，否则页面跳转可能会报错
            for(let i=0;i<this.observers.length;i++){
                let observer = this.observers[i];
                observer.disconnect();
            }
        }
    }
    
    function listenContentElement(app){
        const contentSpan = app.$refs['contentSpanRef'];
        elementResizeListern(app, contentSpan, function(){
            setSliderStyle(app);
        });

        //window size change
        const scrollBarTarget = app.$refs['scrollbarSpanRef'];
        elementResizeListern(app, scrollBarTarget, function(){
            setSliderStyle(app);
        });
    }

    /**
     * set slider style.
     * @param app 
     */
    function setSliderStyle(app){
        if(app.setShowVertical){
            setVerticalSliderStyle(app);
        }
        if(app.setShowHorizontal){
            setHorizontalSliderStyle(app);
        }
        calContentWidth(app);
    }

    /**
     * 监听标签大小的变化。
     * 注：刚进入页面时改变object大小事件不会被触发。
     * @param app 
     * @param element 监听的标签
     * @param callBack 回调方法
     * @return observer 监听对象
     * 
     * @auth zhouhui
     * @since 1.0.0
     */
    function elementResizeListern(app, element, callBack){
        const observer = new MutationObserver(function(mutationsList, observer){
            for(let mutation of mutationsList){
                if(mutation.type === 'attributes' && callBack != null){
                    callBack();
                }
            }
        });
        observer.observe(element,  {attributes: true, childList: false, subtree: true});
        app.observers.push(observer);
        
        const objEl = document.createElement('object');
        objEl.setAttribute('style',
            'display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden;opacity: 0; pointer-events: none; z-index: -10;');
        objEl.type='text/html';
        element.appendChild(objEl);
        objEl.data = 'about:blank';
        objEl.onload = function(){
            this.contentDocument.defaultView.addEventListener('resize',function(e){
                if(callBack != null){
                    callBack();
                }
            });
        }
    }

    /**
     * set sliderY style
     */
    function setVerticalSliderStyle(app){
        if(app.$refs['scrollFixedSpanRef'] == null || app.$refs['contentSpanRef'] == null || app.$refs['scrollbarSpanRef'] == null){
            return;
        }
        const scrollFixedSpanTarget =  app.$refs['scrollFixedSpanRef'];
        let sliderScrollTop = 0;
        let sliderH = 0;
        if(scrollFixedSpanTarget != null){
            sliderScrollTop = scrollFixedSpanTarget.scrollTop;
            sliderH = scrollFixedSpanTarget.offsetHeight - scrollFixedSpanTarget.clientHeight;
        }
        const contentSpanHeight = app.$refs['contentSpanRef'].offsetHeight;
        const scrollbarHeight = app.$refs['scrollbarSpanRef'].offsetHeight;
        const canMoveHeight = contentSpanHeight - scrollbarHeight;

        const canScroll = contentSpanHeight - scrollbarHeight + sliderH;
        let setSliderHeight = 0;
        let curSiteY = 0;
        if(canMoveHeight > 0){
            setSliderHeight = scrollbarHeight / contentSpanHeight * scrollbarHeight + 2 * sliderH;
            const canScrollHeight = scrollbarHeight - setSliderHeight;
            curSiteY = sliderScrollTop / canMoveHeight * canScrollHeight;
        }else{
            setSliderHeight = 0;
        }
        app.verticalSliderStyle.marginTop = curSiteY + 'px';
        app.verticalSliderStyle.height = setSliderHeight + 'px';
    }

    /**
     * set sliderX style
     */
    function setHorizontalSliderStyle(app){
        if(app.$refs['scrollFixedSpanRef'] == null || app.$refs['contentSpanRef'] == null || app.$refs['scrollbarSpanRef'] == null){
            return;
        }
        if(app.setShowVertical){
            app.fixedSliderWidth = app.setSliderWidth + 2;
        }

        const scrollFixedSpanTarget =  app.$refs['scrollFixedSpanRef'];
        const sliderScrollLeft = scrollFixedSpanTarget.scrollLeft;
        const sliderW = scrollFixedSpanTarget.offsetWidth - scrollFixedSpanTarget.clientWidth;

        const contentSpanWeight = app.$refs['contentSpanRef'].offsetWidth;
        const scrollbarWeight = app.$refs['scrollbarSpanRef'].offsetWidth;

        const canMoveWeight = contentSpanWeight - scrollbarWeight;
        const canScroll = contentSpanWeight - scrollbarWeight + sliderW;

        let setSliderWeight = 0;
        let curSiteX = 0;
        if(canMoveWeight > 0){
            setSliderWeight = scrollbarWeight / contentSpanWeight * scrollbarWeight;
            const canScrollWeight = scrollbarWeight - setSliderWeight - 2 * app.fixedSliderWidth;
            curSiteX = sliderScrollLeft / canMoveWeight * canScrollWeight;
            
        }else{
            setSliderWeight = 0;
        }
        app.horizontalSliderStyle.width = setSliderWeight + 'px';
        app.horizontalSliderStyle.marginLeft = curSiteX + 'px';
        // app.sliderSite.x = curSiteX;
        if(canMoveWeight + setSliderWeight - 2 < scrollbarWeight){
            //不能滑动
            app.horizontalSliderStyle.display = "none";
        }else{
            app.horizontalSliderStyle.display = "block";
        }
    }

    /**
     * reset
     */
    function resetSlider(app){
        //y
        app.moveEnterShowY = false;
        app.canMoveSliderY = false;
        app.verticalSliderStyle.backgroundColor = app.setSliderColor;

        //x
        app.moveEnterShowX = false;
        app.canMoveSliderX = false;
        app.horizontalSliderStyle.backgroundColor = app.setSliderColor;
    }

    /**
     *  calculate content span width
     * @param app
     */
    function calContentWidth(app){
        if(app.$refs['scrollbarSpanRef'] == null){
            return;
        }
        const scrollBarTarget = app.$refs['scrollbarSpanRef'];
        const scrollBarWidth = scrollBarTarget.offsetWidth;

        if(app.$slots['default'] != null && app.$slots['default'].length > 0){
            const slotTarget = app.$slots['default'][0].elm;

            if(app.setShowHorizontal){
                const slotWidth = slotTarget.offsetWidth;
                let tempWidth = 0;
                if(scrollBarWidth >= slotWidth){
                    tempWidth = scrollBarWidth;
                }else{
                    tempWidth = slotWidth;
                }
                app.contentSpanStyle.width = tempWidth + 'px';
            }else{
                app.contentSpanStyle.width = scrollBarWidth + 'px';
            }
        }
    }

</script>

<style>
    .scrollbar-container{
        position: relative;
        width: 100%;
        height: 100%;
        overflow: hidden;
        user-select : none;
    }
    .scrollbar-container .scroll-fixed-span{
        height: 100%;
    }
    .scroll-fixed-span .content-span{
        position: relative;
    }
    .scrollbar-container .scrollbar-bar-span{
        position: absolute;
        display: flex;
        z-index: 100;
    }
    .scrollbar-container .vertical-bar-span{
        flex-direction: column;
        width: 9px;
        height: 100%;
        top: 0px;
        right: 2px;
        z-index: 20;
      }
    .scrollbar-container .horizontal-bar-span{
        flex-direction: row;
        width: 100%;
        height: 9px;
        bottom: 2px;
        left: 0px;
        z-index: 10;
    }
    .scrollbar-bar-span .scrollbar-bar-slider{
        position: relative;
        margin-left: auto;
        margin-right: auto;
        border-radius: 2px 2px 2px 2px;
        cursor: pointer;
        overflow: hidden;
    }
    .slider-y{
        width: 100%;
    }
    slider-x{
        height: 100%;
    }
    .scrollbar-bar-span .fixed-slider{
        position: relative;
        height: 100%;
        flex-shrink: 0;
        background: none;
    }
    .fixed-slider-left{
        margin-left: 0px;
    }
    .fixed-slider-right{
        margin-right: 0px;
    }

    .vertical-slider-enter-active, .vertical-slider-leave-active,
    .horizontal-slider-enter-active, .horizontal-slider-leave-active{
        transition : opacity 0.5s;
    }
    .vertical-slider-enter, .vertical-slider-leave-to,
    .horizontal-slider-enter, .horizontal-slider-leave-to
    {
        opacity : 0;
    }
</style>